package net.wanho.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import net.wanho.constant.AuthConstant;
import net.wanho.constant.LoginConstant;
import net.wanho.entity.AuthInfo;
import net.wanho.entity.RoleAuth;
import net.wanho.entity.UserRole;
import net.wanho.mapper.AuthInfoMapper;
import net.wanho.mapper.RoleAuthMapper;
import net.wanho.mapper.UserRoleMapper;
import net.wanho.service.AuthInfoService;
import net.wanho.util.ThreadUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author Administrator
* @description 针对表【auth_info(权限表)】的数据库操作Service实现
* @createDate 2025-05-05 02:08:25
*/
@Service
@RequiredArgsConstructor
public class AuthInfoServiceImpl extends ServiceImpl<AuthInfoMapper, AuthInfo> implements AuthInfoService{
    private final AuthInfoMapper authInfoMapper;
    private final UserRoleMapper userRoleMapper;
    private final RoleAuthMapper roleAuthMapper;
    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 获取用户权限信息
     */
    @SneakyThrows
    @Override
    public Object getAuthList() {
        Integer userId = ThreadUtil.getUserId();
        // 判断redis中是否存在用户权限信息
        Object authList = redisTemplate.opsForValue().get(AuthConstant.AUTH_PREFIX + userId);
        if (Objects.nonNull(authList)) {
            return authList;
        }
        // 获取用户角色
        List<Integer> roleIdList = userRoleMapper.selectList(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, userId)).stream()
                .mapToInt(UserRole::getRoleId)
                .boxed()
                .collect(Collectors.toList());

        if(roleIdList.isEmpty()) {
            throw new RuntimeException("您没有权限！");
        }
        // 获取用户权限
        List<Integer> authIdList = roleAuthMapper.selectList(new LambdaQueryWrapper<RoleAuth>().in(RoleAuth::getRoleId, roleIdList)).stream()
                .mapToInt(RoleAuth::getAuthId)
                .boxed()
                .distinct() // 权限去重
                .collect(Collectors.toList());
        // 获取用户权限信息
        List<AuthInfo> authInfoList = authInfoMapper.selectList(new LambdaQueryWrapper<AuthInfo>()
                .in(AuthInfo::getAuthId, authIdList)
                .orderByAsc(AuthInfo::getAuthOrder));
        // 构建父子关系
        List<AuthInfo> authInfoListVo = createAuthTree(authInfoList);

        redisTemplate.opsForValue().set(AuthConstant.AUTH_PREFIX + userId, authInfoListVo, LoginConstant.LOGIN_EXPIRE, TimeUnit.MINUTES);

        return authInfoListVo;
    }

    @SneakyThrows
    @Override
    public Object getAuthTree() {
        Object authList = redisTemplate.opsForValue().get(AuthConstant.AUTH_TREE);
        if (Objects.nonNull(authList)) {
            return authList;
        }

        LambdaQueryWrapper<AuthInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByAsc(AuthInfo::getAuthOrder);
        List<AuthInfo> authInfoList = baseMapper.selectList(queryWrapper);

        List<AuthInfo> authTree = createAuthTree(authInfoList);
        redisTemplate.opsForValue().set(AuthConstant.AUTH_TREE, authTree);

        return authTree;
    }

    @Override
    public boolean nameCheck(String authName) {
        LambdaQueryWrapper<AuthInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AuthInfo::getAuthName, authName);

        return baseMapper.selectCount(queryWrapper) <= 0;
    }

    @Override
    public boolean urlCheck(String authUrl) {
        LambdaQueryWrapper<AuthInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AuthInfo::getAuthUrl, authUrl);
        return baseMapper.selectCount(queryWrapper) <= 0;
    }

    @Override
    public boolean codeCheck(String authCode) {
        LambdaQueryWrapper<AuthInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AuthInfo::getAuthCode, authCode);
        return baseMapper.selectCount(queryWrapper) <= 0;
    }

    @Override
    public void updateAuthStateById(Integer id, String authState) {
        LambdaUpdateWrapper<AuthInfo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(AuthInfo::getAuthId, id)
                .set(AuthInfo::getAuthState, authState);
        update(updateWrapper);

        redisTemplate.delete(AuthConstant.AUTH_PREFIX + ThreadUtil.getUserId());
        redisTemplate.delete(AuthConstant.AUTH_TREE);
    }

    @Override
    public void removeAuthById(Integer id) {
        baseMapper.deleteById(id);
        redisTemplate.delete(AuthConstant.AUTH_PREFIX + ThreadUtil.getUserId());
        redisTemplate.delete(AuthConstant.AUTH_TREE);
    }

    @Override
    public void saveAuth(AuthInfo authInfo) {
        save(authInfo);
        redisTemplate.delete(AuthConstant.AUTH_TREE);
    }

    private List<AuthInfo> createAuthTree(List<AuthInfo> authInfoList) {
        return authInfoList.stream()
                .filter(authInfo -> authInfo.getParentId() == 0)
                .peek(authInfo -> {
                    List<AuthInfo> children = findChildrenAuth(authInfoList, authInfo);
                    if(Objects.isNull(children)) {
                        children = new ArrayList<>();
                    }
                    authInfo.setChildAuth(children);
                })
                .collect(Collectors.toList());
    }

    private List<AuthInfo> findChildrenAuth(List<AuthInfo> authInfoList, AuthInfo parentAuth){
        return authInfoList.stream()
                .filter(authInfo -> authInfo.getParentId().equals(parentAuth.getAuthId()))
                .peek(authInfo -> {
                    List<AuthInfo> children = findChildrenAuth(authInfoList, authInfo);
                    if(Objects.isNull(children)) {
                        children = new ArrayList<>();
                    }
                    authInfo.setChildAuth(children);
                })
                .collect(Collectors.toList());
    }
}




